package com.example.administrator.demorecyclerview.refresh;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.NestedScrollingChild2;
import android.support.v4.view.NestedScrollingChildHelper;
import android.support.v4.view.NestedScrollingParent2;
import android.support.v4.view.NestedScrollingParentHelper;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.OverScroller;
import android.widget.ProgressBar;

/**
 * Created by Administrator on 2017/11/20.
 */

/**
 * mTotalDownUnconsumed、mTotalUpUnconsumed拖着无限刷新和无限加载时，不准确
 */
public class MySwipeRefreshLayout4 extends ViewGroup implements NestedScrollingParent2, NestedScrollingChild2 {

    private boolean mLoading;
    private boolean mRefreshing;
//    private final int[] mParentOffsetInWindow = new int[2];


    private RecyclerView mTarget;
    private OnLoadListener mLoadListener;
    private SwipeRefreshLayout.OnRefreshListener mRefreshListener;
    private ProgressBar mFooterProgress;
    private ProgressBar mHeaderProgress;
    private boolean mFinished;
    private NestedScrollingParentHelper mNestedScrollingParentHelper;
    private NestedScrollingChildHelper mNestedScrollingChildHelper;

    private OnChildScrollDownCallback mOnChildScrollDownCallback;
    private OnChildScrollUpCallback mOnChildScrollUpCallback;

    private OverScroller mScroller;

    public MySwipeRefreshLayout4(Context context) {
        this(context, null);
    }

    public MySwipeRefreshLayout4(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MySwipeRefreshLayout4(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public void setLoadingFinished(boolean finished) {
        mFinished = finished;
        setLoading(false);
    }

    public void setRefreshingFinished(boolean finished) {
        mFinished = finished;
        setRefreshing(false);
    }


    private void init() {
//        mFooterProgress = new ProgressBar(getContext());
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        mScroller = new OverScroller(getContext());
        mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);

        mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
        setNestedScrollingEnabled(true);
        createHeaderProgress();
        addView(mHeaderProgress);
        createFooterProgress();
        addView(mFooterProgress);

//        setOnChildScrollDownCallback(myOnChildScrollDownCallback);

    }

    public void setOnChildScrollUpCallback(@Nullable OnChildScrollUpCallback callback) {
//        super.setOnChildScrollUpCallback(callback);
        mOnChildScrollUpCallback = callback;
    }

    public void setOnChildScrollDownCallback(OnChildScrollDownCallback callback) {
        mOnChildScrollDownCallback = callback;
    }

    OnChildScrollUpCallback myOnChildScrollUpCallback = new OnChildScrollUpCallback() {
        @Override
        public boolean canChildScrollUp(@NonNull MySwipeRefreshLayout4 parent, @Nullable View child) {
            if (isLoading()) {
                return true;
            } else {
                return mOnChildScrollUpCallback != null && mOnChildScrollUpCallback.canChildScrollUp(parent, child);
            }
        }


    };

    OnChildScrollDownCallback myOnChildScrollDownCallback = new OnChildScrollDownCallback() {
        @Override
        public boolean canChildScrollDown(@NonNull MySwipeRefreshLayout4 parent, @Nullable View child) {
            if (isRefreshing() || isFinished()) {
                return true;
            } else {
                return mOnChildScrollDownCallback != null && mOnChildScrollDownCallback.canChildScrollDown(parent, child);
            }
        }
    };

    public boolean isRefreshing() {
        return mRefreshing;
    }

    public boolean isLoading() {
        return mLoading;
    }

    private void createFooterProgress() {
        if (mFooterProgress == null) {
            mFooterProgress = new ProgressBar(getContext());
            mFooterProgress.setVisibility(View.VISIBLE);
//            addView(mFooterProgress);
        }
    }

    private void createHeaderProgress() {
        if (mHeaderProgress == null) {
            mHeaderProgress = new ProgressBar(getContext());
            mHeaderProgress.setVisibility(View.VISIBLE);
//            addView(mFooterProgress);
        }
    }

    @Override
    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//        if (mHeaderProgress == null) {
//            createHeaderProgress();
//            final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
//            addViewInLayout(mHeaderProgress, getChildCount(), params, true);
//        }
        mHeaderProgress.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.AT_MOST));
//        if (mFooterProgress == null) {
//            createFooterProgress();
//            final LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
//            addViewInLayout(mFooterProgress, getChildCount(), params, true);
//        }
        mFooterProgress.measure(MeasureSpec.makeMeasureSpec(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.AT_MOST));

        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        mTarget.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));


    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {


        final int headerLeft = getPaddingLeft();
        final int headerTop = getPaddingTop() - mHeaderProgress.getMeasuredHeight();
        mHeaderProgress.layout(headerLeft, headerTop, headerLeft + mHeaderProgress.getMeasuredWidth(), headerTop + mHeaderProgress.getMeasuredHeight());


        final int footerLeft = getPaddingLeft();
        final int footerTop = getMeasuredHeight() - getPaddingBottom();
        mFooterProgress.layout(footerLeft, footerTop, footerLeft + mFooterProgress.getMeasuredWidth(), footerTop + mFooterProgress.getMeasuredHeight());

        final View child = mTarget;

        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        final int childLeft = getPaddingLeft();
        final int childTop = getPaddingTop();
        final int childWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
        final int childHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);

    }


    private void ensureTarget() {

        if (mTarget == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (child instanceof RecyclerView) {
                    mTarget = (RecyclerView) child;
//                    return;
                    break;
                }
            }
        }
    }


//    @Override
//    public void setRefreshing(boolean refreshing) {
//        if (mLoading) {
//            if (!refreshing) {
//                super.setRefreshing(false);
//            }
//        } else {
//            super.setRefreshing(refreshing);
//        }
//
//    }


    public void setOnLoadListener(OnLoadListener listener) {
        mLoadListener = listener;
    }

    public void setOnRefreshListener(SwipeRefreshLayout.OnRefreshListener listener) {
        mRefreshListener = listener;
    }


    @Override
    public void setNestedScrollingEnabled(boolean enabled) {
        mNestedScrollingChildHelper.setNestedScrollingEnabled(enabled);
    }

    @Override
    public boolean isNestedScrollingEnabled() {
        return mNestedScrollingChildHelper.isNestedScrollingEnabled();
    }

    @Override
    public boolean startNestedScroll(int axes, int type) {
        return mNestedScrollingChildHelper.startNestedScroll(axes, type);
    }

    @Override
    public void stopNestedScroll(int type) {
        mNestedScrollingChildHelper.stopNestedScroll(type);
    }

    @Override
    public boolean hasNestedScrollingParent(int type) {
        return mNestedScrollingChildHelper.hasNestedScrollingParent(type);
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type) {
        return mNestedScrollingChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow, int type) {
        return mNestedScrollingChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type);
    }

    @Override
    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
        return mNestedScrollingChildHelper.dispatchNestedPreFling(velocityX, velocityY);
    }

    @Override
    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
        return mNestedScrollingChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) {
        return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;


    }

    @Override
    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes, int type) {
//        onNestedScrollAccepted(child, target, axes);
        mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes, type);
        startNestedScroll(axes, type);
    }

    @Override
    public void onStopNestedScroll(@NonNull View target, int type) {
//        onStopNestedScroll(target);
        finishToRefresh();

        stopNestedScroll(type);
        mNestedScrollingParentHelper.onStopNestedScroll(target, type);
    }


    private int mTotalUnconsumed;

    private boolean canNotifyUser(int dy) {
        boolean isBusy = isBusy();
        if (isBusy) {
            return false;
        } else {
            boolean scrollDown = dy > 0;

            return scrollDown ? !mFinished && !canChildScrollDown() : !canChildScrollUp();
        }


//        return !isBusy && scrollDown ? !mFinished : false && dy < 0 ? !canChildScrollUp() : !canChildScrollDown() && mScroller.isFinished();
    }

    private void moveChild(int top, boolean notifyUser) {
        if (top == 0) {
//            Log.i("@@@@@@", "@@@@@@@:" + top);
        }
        scrollTo(0, top);
        if (notifyUser) {
            doRefreshOrLoading(top);
        }
    }

    private void doRefreshOrLoading(int top) {
        if (top < 0) {

//            setRefreshing(true, true);
            if (mHeaderProgress.getVisibility() != VISIBLE) {
                mHeaderProgress.setVisibility(VISIBLE);
            }
        } else if (top > 0) {

            setLoading(true, true);
            if (mFooterProgress.getVisibility() != VISIBLE) {
                mFooterProgress.setVisibility(VISIBLE);
            }

        }


    }


    @Override
    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null, type);

//        if (dyUnconsumed != 0) {
//            final int dy = dyUnconsumed;
//            boolean canScroll = dy > 0 || type == ViewCompat.TYPE_TOUCH;
//            if (canScroll) {
//                mTotalUnconsumed -= dy;
//                mTotalUnconsumed = Math.max(-mHeaderProgress.getHeight(), Math.min(mFooterProgress.getHeight(), mTotalUnconsumed));
//                boolean canNotifyUser = canNotifyUser(dy);
//
////                Log.i("@@@@@@@:", "@@@@@:" + dyUnconsumed + "," + mTotalUnconsumed);
//                moveChild(-mTotalUnconsumed, canNotifyUser);
//            }
//
//
////            if (dy < 0 && !canChildScrollUp() && mScroller.isFinished()) {
////                mTotalUpUnconsumed -= dy;
//////            Log.i("@@@@@@@@","@@@@scroll"+mTotalUpUnconsumed+","+dyUnconsumed);
////
////                final int offset = mTotalUpUnconsumed - mHeaderProgress.getMeasuredHeight();
////                if (offset > 0) {
////                    mTotalUpUnconsumed = mHeaderProgress.getMeasuredHeight();
////                }
////                moveHeader(-mTotalUpUnconsumed);
////
////
//////            scrollTo(0,-mTotalUpUnconsumed);
////
////            }
////
////
////            if (dy > 0 && !canChildScrollDown() && mScroller.isFinished()) {
////                mTotalDownUnconsumed -= dy;
////
////                final int offset = mTotalDownUnconsumed + mFooterProgress.getMeasuredHeight();
////                if (offset < 0) {
////                    mTotalDownUnconsumed = -mFooterProgress.getMeasuredHeight();
////                }
////                moveFooter(-mTotalDownUnconsumed);
////
////            }
//        }

        if (dyUnconsumed < 0) {
            final int dy = dyUnconsumed;
            boolean canScroll = dy > 0 || type == ViewCompat.TYPE_TOUCH;
            if (canScroll) {
                mTotalUnconsumed -= dy;
                mTotalUnconsumed = Math.max(-mHeaderProgress.getHeight(), Math.min(mFooterProgress.getHeight(), mTotalUnconsumed));
                boolean canNotifyUser = canNotifyUser(dy);

//                Log.i("@@@@@@@:", "@@@@@:" + dyUnconsumed + "," + mTotalUnconsumed);
                moveChild(-mTotalUnconsumed, canNotifyUser);
            }
        }


    }

    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @Nullable int[] consumed, int type) {

//        if (mTotalUnconsumed != 0) {
//            int consumedY = dy < 0 ? Math.max(mTotalUnconsumed, dy) : Math.min(mTotalUnconsumed, dy);
//            consumed[1] = consumedY;
//            mTotalUnconsumed -= consumedY;
//            moveChild(-mTotalUnconsumed, false);
//        }
        Log.i("@@@@@@@:", "@@@@@:" + dy + "," + mTotalUnconsumed);

        if (dy > 0 && mTotalUnconsumed > 0) {
            int consumedY = dy < 0 ? Math.max(mTotalUnconsumed, dy) : Math.min(mTotalUnconsumed, dy);
            consumed[1] = consumedY;
            mTotalUnconsumed -= consumedY;
            moveChild(-mTotalUnconsumed, false);
        }


//        if (dy > 0 && mTotalUpUnconsumed > 0) {
//            if (dy > mTotalUpUnconsumed) {
//                consumed[1] = mTotalUpUnconsumed;
//                mTotalUpUnconsumed = 0;
//            } else {
//                mTotalUpUnconsumed -= dy;
//                consumed[1] = dy;
//            }
//            moveFooter(-mTotalUpUnconsumed);
//
//        }
//        if (dy > 0 && mTotalUpUnconsumed == 0 && dy - consumed[1] > 0) {
//            mHeaderProgress.setVisibility(GONE);
//        }
//
//
//        if (dy < 0 && mTotalDownUnconsumed < 0 && mScroller.isFinished()) {
//            if (dy < mTotalDownUnconsumed) {
//                consumed[1] = mTotalDownUnconsumed;
//                mTotalDownUnconsumed = 0;
//            } else {
//                mTotalDownUnconsumed -= dy;
//                consumed[1] = dy;
//            }
//            moveFooter(-mTotalDownUnconsumed);
//        }
//
//        if (dy < 0 && mTotalDownUnconsumed == 0
//                && dy - consumed[1] < 0) {
//            mFooterProgress.setVisibility(View.GONE);
//        }
////
//        if (type == ViewCompat.TYPE_TOUCH) {
//            onNestedPreScroll(target, dx, dy, consumed);
//        } else {
////            dispatchNestedPreScroll(dx, dy, consumed, null);
//            dispatchNestedPreScroll(dx, dy, consumed, null);
//        }


        dispatchNestedPreScroll(dx, dy, consumed, null, type);

    }

    @Override
    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
        return dispatchNestedFling(velocityX, velocityY, consumed);
    }

    @Override
    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
        return dispatchNestedPreFling(velocityX, velocityY);
    }

    @Override
    public int getNestedScrollAxes() {
        return mNestedScrollingParentHelper.getNestedScrollAxes();
    }

    public interface OnLoadListener {
        void onLoading();
    }

    private boolean mIsBeginDragged = false;
    //    private float mInitialDownY;
//    private float mInitialMotionY;
    private float mLastMotionY;
    private int mTouchSlop;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ensureTarget();
        /**
         *
         * 如果正在loading或者loading结束后正在scrolling,onStartNestedScroll会返回false,此时会得到触摸时间，所以要判断mLoading||!mScroller.isFinished()
         * */
        if (!mScroller.isFinished())
            return false;

        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN: {
                mIsBeginDragged = false;
                mLastMotionY = ev.getY();
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                final float y = ev.getY();
                final float yDiff = Math.abs(y - mLastMotionY);
                if (yDiff > mTouchSlop && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) == 0) {
                    mLastMotionY = y;
                    mIsBeginDragged = true;
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                }

                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mIsBeginDragged = false;
                stopNestedScroll(ViewCompat.TYPE_TOUCH);
                break;

        }


        return mIsBeginDragged;
    }

    private final int[] mScrollOffset = new int[2];
    private final int[] mScrollConsumed = new int[2];
    private int mNestedYOffset;

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        /**
         *
         * 如果正在loading或者loading结束后正在scrolling,onStartNestedScroll会返回false,此时会得到触摸时间，所以要判断mLoading||!mScroller.isFinished()
         * */

        if (!mScroller.isFinished())
            return false;

        MotionEvent vtev = MotionEvent.obtain(ev);
        vtev.offsetLocation(0, mNestedYOffset);

        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mIsBeginDragged = false;
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
                break;
            case MotionEvent.ACTION_MOVE:
                final float y = ev.getY();
                int deltaY = (int) (mLastMotionY - y);
                if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset,
                        ViewCompat.TYPE_TOUCH)) {
                    deltaY -= mScrollConsumed[1];
                    vtev.offsetLocation(0, mScrollOffset[1]);
                    mNestedYOffset += mScrollOffset[1];
                }


                if (Math.abs(deltaY) > mTouchSlop && !mIsBeginDragged) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    mIsBeginDragged = true;
                    if (deltaY > 0) {
                        deltaY -= mTouchSlop;
                    } else {
                        deltaY += mTouchSlop;
                    }
                }

                if (mIsBeginDragged) {
                    mLastMotionY = y - mScrollOffset[1];

                }
                final int oldY = getScrollY();
                if (deltaY != 0) {
//                    Log.i("@@@@@", "@@@@@@@@:deltaY" + deltaY);

                    final int range = getScrollRange(deltaY);
                    scrollVertical(oldY, deltaY, range);
                }

                final int scrolledDeltaY = getScrollY() - oldY;
                final int unconsumedY = deltaY - scrolledDeltaY;
                if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset,
                        ViewCompat.TYPE_TOUCH)) {
                    mLastMotionY -= mScrollOffset[1];
                    vtev.offsetLocation(0, mScrollOffset[1]);
                    mNestedYOffset += mScrollOffset[1];
                }

                break;
            case MotionEvent.ACTION_UP:
                if (mIsBeginDragged) {
                    finishToRefresh();
                }
                mIsBeginDragged = false;
                stopNestedScroll(ViewCompat.TYPE_TOUCH);
                break;
            case MotionEvent.ACTION_CANCEL:
                mIsBeginDragged = false;
                stopNestedScroll(ViewCompat.TYPE_TOUCH);
                break;
        }


        return true;
    }

    private void finishToRefresh() {
        if (mTotalUnconsumed > 0 && !isBusy()) {
            setRefreshing(true, true);
        }
    }

    private boolean isBusy() {
        return mRefreshing || mLoading;
    }


    private int scrollVertical(int oldScrollY, int deltaY, int range) {
//        int unconsumedY;
//        range -= oldScrollY;
        int scroll = 0;
        int newScrollY = oldScrollY + deltaY;

        if (deltaY > 0) {
            if (newScrollY > range) {
                scroll = range;
            } else {
                scroll = newScrollY;
            }
        } else if (deltaY < 0) {
            if (newScrollY < range) {
                scroll = range;
            } else {
                scroll = newScrollY;
            }
        }
        mTotalUnconsumed = -newScrollY;
//        Log.i("@@@@@@@", "@@@@newScrollY" + newScrollY);
        boolean canNotifyUser = canNotifyUser(deltaY);
        moveChild(-mTotalUnconsumed, canNotifyUser);

//        Log.i("@@@@@@@", "@@@@" + scroll);

//        if (deltaY > 0) {
//            //loading
//
//
//            if (deltaY > range) {
//                scroll = range;
//            } else {
//                scroll = deltaY;
//            }
//
//
//        } else if (deltaY < 0) {
//            if (deltaY < range) {
//                scroll = range;
//            } else {
//                scroll = deltaY;
//            }
//
//
//            //refreshing
//        }
        scrollTo(0, scroll);
        return scroll;


    }

    int getScrollRange(int deltaY) {
        int scrollRange = 0;
        if (deltaY > 0) {
            View downView = mFooterProgress;
            scrollRange = downView.getMeasuredHeight();

        } else if (deltaY < 0) {
            View upView = mHeaderProgress;
            scrollRange = -upView.getMeasuredHeight();
        }
        return scrollRange;
    }
//    int getScrollRange(boolean down) {
//        int scrollRange = 0;
//        if (down) {
//            View downView = mFooterProgress;
//            scrollRange = downView.getHeight() + (getHeight() - getPaddingTop() - getPaddingBottom());
//
//        } else {
//            View upView = mHeaderProgress;
//            scrollRange = getPaddingTop() - upView.getHeight();
//
//
//        }
//
//        return scrollRange;
//    }


    public boolean isFinished() {
        return mFinished;
    }


    private void performeLoadingCallback() {
        if (mLoadListener != null) {
            mLoadListener.onLoading();
        }
    }

    private void performeRefreshingCallback() {
        if (mRefreshListener != null) {
            mRefreshListener.onRefresh();
            Log.i("@@@@@", "@@@@@@@@:finishToRef");

        }
    }

    public void setLoading(boolean loading) {
        if (loading && mLoading != loading) {
            setLoading(loading, true);
        } else {
            setLoading(loading, false);
        }
    }

    private void setLoading(boolean loading, boolean notify) {
        if (mLoading != loading) {
            ensureTarget();
            mLoading = loading;
            if (mLoading) {
                if (notify && !mFinished) {
                    performeLoadingCallback();
                }
            } else {
                resetLoading();
            }
        }
    }

    public void setRefreshing(boolean refreshing) {
        if (refreshing && mRefreshing != refreshing) {
            setRefreshing(refreshing, true);
        } else {
            setRefreshing(refreshing, false);
        }
    }

    private void setRefreshing(boolean refreshing, boolean notify) {
        if (mRefreshing != refreshing) {
            ensureTarget();
            mRefreshing = refreshing;
            if (mRefreshing) {
                if (notify) {
                    performeRefreshingCallback();
                }
            } else {
                resetRefresh();
            }
        }
    }


    private void resetLoading() {
//        if (mTotalDownUnconsumed != 0) {
//            mScroller.startScroll(0, mTotalDownUnconsumed, 0, -mTotalDownUnconsumed);
//            ViewCompat.postOnAnimation(this, mScrollRunnable);
//        } else {
//            mFooterProgress.setVisibility(View.GONE);
//            moveFooter(0);
//        }
//                ((RecyclerView) mTarget).stopNestedScroll();
        mTarget.stopScroll();

        if (mTotalUnconsumed < 0) {
            mTarget.scrollBy(0, -mTotalUnconsumed);
            mTotalUnconsumed = 0;
//            moveFooter(0);
            moveChild(0, false);
            if (mHeaderProgress.getVisibility() != GONE) {
                mHeaderProgress.setVisibility(GONE);
            }

        }

    }

    private void resetRefresh() {


        mTarget.stopScroll();

//        mScroller.startScroll(0, mTotalUpUnconsumed, 0, -mTotalUpUnconsumed);
//        Log.i("@@@@@", "@@@@@@@resetRefresh:" + mTotalUpUnconsumed);
//
//        ViewCompat.postOnAnimation(this, mScrollRunnable);

        if (mTotalUnconsumed > 0) {
            mTotalUnconsumed = 0;
            moveChild(0, false);
            if (mFooterProgress.getVisibility() != GONE) {
                mFooterProgress.setVisibility(GONE);
            }
        }


//        mHeaderProgress.setVisibility(View.GONE);
//        moveHeader(mTotalUpUnconsumed = 0);


    }


//    private final Runnable mScrollRunnable = new Runnable() {
//        @Override
//        public void run() {
//            if (mScroller.computeScrollOffset()) {
////                Log.i("@@@@@@@", "@@@@@@@@:computeScroll:" + mScroller.getCurrY());
//
//
//                final int curr = mScroller.getCurrY();
//                if (curr < 0) {
//                    mTotalDownUnconsumed = curr;
////                moveFooter(-mTotalDownUnconsumed);
//                    scrollTo(0, -mTotalDownUnconsumed);
//
//
//                } else if (curr > 0) {
//                    mTotalUpUnconsumed = curr;
//                    scrollTo(0, -mTotalUpUnconsumed);
//                } else {
//                    mTotalDownUnconsumed = 0;
//                    mTotalUpUnconsumed = 0;
//
//                    mFooterProgress.setVisibility(GONE);
//                    mHeaderProgress.setVisibility(GONE);
//                }
//                Log.i("@@@@@", "@@@@@@@Runnable:" + mTotalUpUnconsumed);
//
//
////                mTotalDownUnconsumed -= mScroller.getCurrY();
//
//
////                try {
////                    Thread.sleep(100);
////                } catch (InterruptedException e) {
////                    e.printStackTrace();
////                }
//
////                moveFooter();
//
////                moveFooter(mTotalDownUnconsumed);
////                scrollTo(0,mScroller.getCurrY());
//
//                if (curr != 0) {
//                    ViewCompat.postOnAnimation(MySwipeRefreshLayout.this, this);
//                } else {
//                    mScroller.forceFinished(true);
//                }
//
//            }
//        }
//    };


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
//        resetLoading();
//        resetRefresh();
    }

    public interface OnChildScrollUpCallback {
        boolean canChildScrollUp(@NonNull MySwipeRefreshLayout4 parent, @Nullable View child);
    }

    public boolean canChildScrollDown() {
        if (mOnChildScrollDownCallback != null) {
            return mOnChildScrollDownCallback.canChildScrollDown(this, mTarget);
        }
        return mTarget == null ? false : mTarget.canScrollVertically(1);


//        return false;
    }

    public boolean canChildScrollUp() {
//        if (myOnChildScrollUpCallback != null) {
//            return myOnChildScrollUpCallback.canChildScrollUp(this, mTarget);
//        }
        if (mOnChildScrollUpCallback != null) {
            return mOnChildScrollUpCallback.canChildScrollUp(this, mTarget);
        }
        return mTarget == null ? false : mTarget.canScrollVertically(-1);
    }


    public static class EarlyScrollListener extends RecyclerView.OnScrollListener {
        /**
         * RecyclerView滑动的时候，滑动到倒数几个的时候，进行预先loading
         */
        private int mEndNum;

        public EarlyScrollListener(MySwipeRefreshLayout4 refreshLayout, int endNum) {
            this.mRefreshLayout = refreshLayout;
            this.mEndNum = endNum;
        }

        MySwipeRefreshLayout4 mRefreshLayout;
        private int mState;
        private boolean mLastVisible;

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            mState = newState;
            doLoading();
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            final RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(recyclerView.getAdapter() == null ? -1 : recyclerView.getAdapter().getItemCount() - mEndNum);
            mLastVisible = viewHolder != null;
            doLoading();

        }

        private void doLoading() {
            if (!mRefreshLayout.isRefreshing() && !mRefreshLayout.isLoading() && mLastVisible && mState != RecyclerView.SCROLL_STATE_IDLE && !mRefreshLayout.isFinished()) {
                mRefreshLayout.setLoading(true);
            }
        }
    }

    public interface OnChildScrollDownCallback {
        boolean canChildScrollDown(@NonNull MySwipeRefreshLayout4 parent, @Nullable View child);
    }

    //    @Override
//    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
//        boolean val = super.onStartNestedScroll(child, target, nestedScrollAxes);
//        Log.i("##", "onStartNestedScroll:" + val);
//        return val;
//    }
//
//    @Override
//    public void onNestedScrollAccepted(View child, View target, int axes) {
//        super.onNestedScrollAccepted(child, target, axes);
//        Log.i("##", "onNestedScrollAccepted:");
//
//    }

//    @Override
//    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
////        boolean val = super.onNestedPreFling(target, velocityX, velocityY);
////        Log.i("##", "onNestedPreFling:" + val + "," + velocityY);
////        return val;
//        return false;
//    }
//
//    @Override
//    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
//        boolean val = super.onNestedFling(target, velocityX, velocityY, consumed);
////        Log.i("##", "onNestedFling:" + val + "," + velocityY + "," + consumed);
//        return val;
//    }


//    @Override
//    public void onStopNestedScroll(View child) {
//        super.onStopNestedScroll(child);
//        Log.i("##", "onStopNestedScroll");
//    }
}
